#!/usr/bin/env python
from pygame import *
from math import ceil
from Const import REGION_WIDTH, REGION_HEIGHT
from Objects.Ground import Ground
from Objects.Barrel import Barrel
from Objects.Player import Player
from Objects.Enemy import *
from Objects.Spikes import Spikes
from Objects.Pickups.Coin import Coin
from Particles.PartBlood import PartBlood
from Load import read, make_readable
from Camera import Camera

class Level:
    def __init__(self, path, il, screen):
        self.il = il
        self.camera = Camera(screen, self)
        self.player = None
        self.timer_resetplayer = False
        self.timer_resetplayer_time = 2#in seconden
        self.timer_resetplayer_tick = 0
        self.load(path)
        self.remove_list = []
    
    def preload(self, path):
        #loads all level globals + regions        
        properties = read(path, "Properties", 7)
        self.level_width = int(properties[0][0])
        self.level_height = int(properties[0][1])
        self.count_ground = int(properties[1][0])
        self.count_barrels = int(properties[2][0])
        self.count_enemy1 = int(properties[3][0])
        self.count_enemy2 = int(properties[4][0])
        self.count_spikes = int(properties[5][0])
        self.count_coins = int(properties[6][0])
        
        hor_regions = int(ceil(float(self.level_width) / REGION_WIDTH))
        vert_regions = int(ceil(float(self.level_height) / REGION_HEIGHT))

        index = 1
        self.region_indices = []
        for x in range(0, hor_regions):
            self.region_indices.append([])
            for y in range(0, vert_regions):               
                self.region_indices[x].append(index)
                index += 1
        self.hor_regions = hor_regions
        self.vert_regions = vert_regions
        self.regions = []
        for i in range(0, index):
            self.regions.append([])

        self.update_list = []
        self.draw_list = []
        self.part_front_list = []
        self.part_back_list = []
    
    def load(self, path):
        if path == "":
            return
        path = "Data/Levels/" + path
        path = make_readable(path)
        self.preload(path)
        self.level_path = path
        
        ground = read(path, "Ground", self.count_ground)
        for i in range(0, self.count_ground):
            obj = Ground(self, self.il, int(ground[i][0]), int(ground[i][1]), int(ground[i][7]))
            obj.destroyable = bool(ground[i][2])
            obj.health = int(ground[i][3])
            obj.solid = bool(ground[i][4])
            if obj.solid:
                for r in obj.region:
                    self.regions[r].append(obj)
            obj.friction = float(ground[i][5])
            obj.bounce = float(ground[i][6])         
            self.draw_list.append(obj)
        for o in self.draw_list:
            if isinstance(o, Ground):
                o.set_image_index(o.find_image_index(self), self.il)
        del ground
        
        self.standard_load(path, "Barrel", self.count_barrels, Barrel(self, self.il, 0, 0), True)      
        self.standard_load(path, "Enemy1", self.count_enemy1, Enemy1(self, self.il, 0, 0), True)
        self.standard_load(path, "Enemy2", self.count_enemy2, Enemy2(self, self.il, 0, 0), True) 
        self.standard_load(path, "Player", 1, Player(self, self.il, 0, 0), True)
        self.player = self.update_list[-1]
        self.camera.object = self.player
        self.standard_load(path, "Spikes", self.count_spikes, Spikes(self, self.il, 0, 0), False)
        self.standard_load(path, "Coins", self.count_coins, Coin(self, self.il, 0, 0), False)
        
    def standard_load(self, path, section, count, type_object, physic):
        temp = read(path, section, count)
        for i in range(0, count):
            obj = type_object.get_new_instance(self, self.il)
            obj.__init__(self, self.il, int(temp[i][0]), int(temp[i][1]))
            obj.destroyable = bool(temp[i][2])
            obj.health = int(temp[i][3])
            obj.solid = bool(temp[i][4])
            if obj.solid or not physic:
                for r in obj.region:
                    self.regions[r].append(obj)
            obj.friction = float(temp[i][5])
            obj.bounce = float(temp[i][6])            
            self.draw_list.append(obj)
            if physic:
                self.update_list.append(obj)
        del temp
       
    def change_region(self, obj, from_, to_):
        for f in from_:
            if to_.__contains__(f):
               to_.remove(f)
            else:
                if self.regions[f].__contains__(obj):
                    self.regions[f].remove(obj)          
        #for r in self.regions:
        #    if r.__contains__(obj):
        #        r.remove(obj)
        for t in to_:
            self.regions[t].append(obj)
            
    def remove(self, obj, region):
        self.remove_list.append(obj)
    
    def flush_remove_list(self):
        #for r in region:
        #    if self.regions[r].__contains__(obj):
        #        self.regions[r].remove(obj)
        if len(self.remove_list) <= 0:
            return
        print "--->remove init<---"
        print "removing " + str(self.remove_list)
        print "##1#update list####"
        print str(self.update_list)
        for obj in self.remove_list:
            for r in self.regions:
                if r.__contains__(obj):
                    r.remove(obj)
            if self.update_list.__contains__(obj):
                self.update_list.remove(obj)
            if self.draw_list.__contains__(obj):
                self.draw_list.remove(obj)
        self.remove_list = []
        print "##2#update list####"
        print str(self.update_list)
        print "<---remove done--->"
    
    def remove_part(self, part):
        if self.part_front_list.__contains__(part):
            self.part_front_list.remove(part)
        elif self.part_back_list.__contains__(part):
            self.part_back_list.remove(part)
        
    def find_collision(self, rect, region, other, all, onlysolid):
        ret = []
        for o in self.regions[region]:
            if o == other:
                continue
            if not o.solid:
                if onlysolid:
                    continue
            if (rect[0] + rect[2] > o.rect[0] and
                rect[0] < o.rect[0] + o.rect[2] and
                rect[1] + rect[3] > o.rect[1] and
                rect[1] < o.rect[1] + o.rect[3]):
                ret.append(o)
                if not all:
                    break
        return ret
    
    def update(self, events, fps):
        for o in self.update_list:
            o.update(self, events, fps)
        for p in self.part_front_list:
            p.update(self, fps)
        for p in self.part_back_list:
            p.update(self, fps)
        self.flush_remove_list()    
        if self.timer_resetplayer:
            if self.timer_resetplayer_tick < self.timer_resetplayer_time * fps:
                self.timer_resetplayer_tick += 1
            else:
                self.timer_resetplayer = False
                self.reset_player()
    
    def set_timer_resetplayer(self):
        self.timer_resetplayer = True
        self.timer_resetplayer_tick = 0
    
    def reset_player(self):
        self.standard_load(self.level_path, "Player", 1, Player(self, self.il, 0, 0), True)
        self.player = self.update_list[-1]
        self.camera.object = self.player
        
    def draw(self):
        for p in self.part_back_list:
            p.draw(self.camera)
        for i in self.draw_list:
            i.draw(self.camera)
        for p in self.part_front_list:
            p.draw(self.camera)
    #
    def create_blood(self, x, y):
        self.part_front_list.append(PartBlood(x, y, self.il))